<!DOCTYPE html>
<html lang="zh-CN">
<head>
  <meta charset="UTF-8">
  <meta name="viewport" content="width=device-width, initial-scale=1.0">
  <title>HTML元素拖动示例</title>
  <script src="https://cdn.tailwindcss.com"></script>
  <link href="https://cdn.jsdelivr.net/npm/font-awesome@4.7.0/css/font-awesome.min.css" rel="stylesheet">

  <script>
    tailwind.config = {
      theme: {
        extend: {
          colors: {
            primary: '#4F46E5',
            secondary: '#10B981',
            accent: '#F59E0B',
            danger: '#EF4444',
            dark: '#1E293B',
          },
          fontFamily: {
            inter: ['Inter', 'system-ui', 'sans-serif'],
          },
        }
      }
    }
  </script>

  <style type="text/tailwindcss">
    @layer utilities {
      .content-auto {
        content-visibility: auto;
      }
      .draggable {
        cursor: grab;
        transition: all 0.2s ease;
      }
      .draggable:active {
        cursor: grabbing;
        transform: scale(1.02);
      }
      .drop-zone {
        transition: all 0.3s ease;
      }
      .drop-zone.highlight {
        background-color: rgba(79, 70, 229, 0.1);
        border-color: #4F46E5;
      }
      .item-list {
        min-height: 40px;
      }
    }
  </style>
</head>
<body class="bg-gray-50 font-inter text-dark min-h-screen">
<header class="bg-white shadow-sm py-6">
  <div class="container mx-auto px-4 sm:px-6 lg:px-8">
    <h1 class="text-[clamp(1.5rem,3vw,2.5rem)] font-bold text-primary">
      <i class="fa fa-arrows mr-2"></i>HTML元素拖动示例
    </h1>
    <p class="text-gray-600 mt-2">展示原生HTML拖放API的多种用法和交互效果</p>
  </div>
</header>

<main class="container mx-auto px-4 sm:px-6 lg:px-8 py-8">
  <!-- 基础拖动示例 -->
  <section class="mb-12 bg-white rounded-xl shadow-md p-6">
    <h2 class="text-xl font-bold mb-4 flex items-center">
      <i class="fa fa-square-o text-primary mr-2" draggable="true"></i>基础拖动元素
    </h2>
    <p class="text-gray-600 mb-4">可自由拖动的元素，不受约束</p>

    <div class="relative h-64 bg-gray-50 rounded-lg border border-gray-200 overflow-hidden">
      <div id="freeDraggable" class="draggable absolute w-24 h-24 bg-primary text-white rounded-lg flex items-center justify-center shadow-md" style="top: 20px; left: 20px;">
        <span>拖动我</span>
      </div>

      <div class="absolute top-4 right-4 bg-white/80 backdrop-blur-sm px-3 py-2 rounded-full text-sm shadow-sm">
        <i class="fa fa-info-circle text-primary mr-1"></i> 可自由移动
      </div>
    </div>
  </section>

  <!-- 拖放排序示例 -->
  <section class="mb-12 bg-white rounded-xl shadow-md p-6">
    <h2 class="text-xl font-bold mb-4 flex items-center">
      <i class="fa fa-list-ol text-secondary mr-2"></i>拖放排序
    </h2>
    <p class="text-gray-600 mb-4">拖动项目可以改变它们的顺序</p>

    <div id="sortableList" class="space-y-2 max-w-md">
      <div class="draggable item-list bg-gray-50 border border-gray-200 rounded-lg p-4 flex items-center" draggable="true">
        <div class="w-8 h-8 bg-secondary/20 text-secondary rounded-full flex items-center justify-center mr-3">
          <i class="fa fa-file-text-o"></i>
        </div>
        <span>文档文件 1</span>
      </div>

      <div class="draggable item-list bg-gray-50 border border-gray-200 rounded-lg p-4 flex items-center" draggable="true">
        <div class="w-8 h-8 bg-secondary/20 text-secondary rounded-full flex items-center justify-center mr-3">
          <i class="fa fa-image"></i>
        </div>
        <span>图片文件 2</span>
      </div>

      <div class="draggable item-list bg-gray-50 border border-gray-200 rounded-lg p-4 flex items-center" draggable="true">
        <div class="w-8 h-8 bg-secondary/20 text-secondary rounded-full flex items-center justify-center mr-3">
          <i class="fa fa-music"></i>
        </div>
        <span>音频文件 3</span>
      </div>

      <div class="draggable item-list bg-gray-50 border border-gray-200 rounded-lg p-4 flex items-center" draggable="true">
        <div class="w-8 h-8 bg-secondary/20 text-secondary rounded-full flex items-center justify-center mr-3">
          <i class="fa fa-video-camera"></i>
        </div>
        <span>视频文件 4</span>
      </div>
    </div>
  </section>

  <!-- 拖放分类示例 -->
  <section class="mb-12 bg-white rounded-xl shadow-md p-6">
    <h2 class="text-xl font-bold mb-4 flex items-center">
      <i class="fa fa-folder-open text-accent mr-2"></i>拖放分类
    </h2>
    <p class="text-gray-600 mb-4">将项目拖放到不同的分类区域</p>

    <div class="grid grid-cols-1 md:grid-cols-3 gap-6">
      <!-- 可拖动项目 -->
      <div class="drop-zone border-2 border-dashed border-gray-300 rounded-lg p-4">
        <h3 class="font-medium text-center mb-3">可拖动项目</h3>
        <div class="space-y-2">
          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true" data-type="work">
            <i class="fa fa-briefcase text-primary mr-2"></i>
            <span>工作文档</span>
          </div>

          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true" data-type="personal">
            <i class="fa fa-user text-accent mr-2"></i>
            <span>个人笔记</span>
          </div>

          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true" data-type="work">
            <i class="fa fa-calendar text-primary mr-2"></i>
            <span>会议安排</span>
          </div>

          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true" data-type="personal">
            <i class="fa fa-shopping-cart text-accent mr-2"></i>
            <span>购物清单</span>
          </div>
        </div>
      </div>

      <!-- 工作分类 -->
      <div class="drop-zone border-2 border-dashed border-gray-300 rounded-lg p-4" data-accept="work">
        <h3 class="font-medium text-center mb-3 text-primary">工作</h3>
        <div class="space-y-2 min-h-[120px]"></div>
      </div>

      <!-- 个人分类 -->
      <div class="drop-zone border-2 border-dashed border-gray-300 rounded-lg p-4" data-accept="personal">
        <h3 class="font-medium text-center mb-3 text-accent">个人</h3>
        <div class="space-y-2 min-h-[120px]"></div>
      </div>
    </div>
  </section>

  <!-- 拖放删除示例 -->
  <section class="bg-white rounded-xl shadow-md p-6">
    <h2 class="text-xl font-bold mb-4 flex items-center">
      <i class="fa fa-trash text-danger mr-2"></i>拖放删除
    </h2>
    <p class="text-gray-600 mb-4">将项目拖到垃圾桶进行删除</p>

    <div class="flex flex-col md:flex-row gap-6 items-center">
      <div class="flex-1">
        <div class="space-y-2">
          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true">
            <i class="fa fa-file-o text-gray-500 mr-2"></i>
            <span>临时文件 1.txt</span>
          </div>

          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true">
            <i class="fa fa-file-o text-gray-500 mr-2"></i>
            <span>草稿文档.docx</span>
          </div>

          <div class="draggable bg-white border border-gray-200 rounded-lg p-3 flex items-center shadow-sm" draggable="true">
            <i class="fa fa-file-o text-gray-500 mr-2"></i>
            <span>备份照片.jpg</span>
          </div>
        </div>
      </div>

      <div id="trashZone" class="drop-zone border-2 border-dashed border-danger rounded-lg p-8 flex flex-col items-center justify-center w-48 h-48">
        <i class="fa fa-trash-o text-5xl text-danger/70 mb-3"></i>
        <span class="text-danger font-medium">拖到此处删除</span>
      </div>
    </div>
  </section>
</main>

<footer class="bg-white border-t border-gray-200 py-6 mt-12">
  <div class="container mx-auto px-4 sm:px-6 lg:px-8 text-center text-gray-600 text-sm">
    <p>使用 HTML5 拖放 API 实现 | 支持现代浏览器</p>
  </div>
</footer>

<script>
  // 基础自由拖动功能
  const freeDraggable = document.getElementById('freeDraggable');
  let isDragging = false;
  let offsetX, offsetY;

  freeDraggable.addEventListener('mousedown', startDrag);
  document.addEventListener('mousemove', drag);
  document.addEventListener('mouseup', endDrag);

  function startDrag(e) {
    // 计算鼠标相对于元素的位置
    offsetX = e.clientX - freeDraggable.getBoundingClientRect().left;
    offsetY = e.clientY - freeDraggable.getBoundingClientRect().top;
    isDragging = true;
    freeDraggable.classList.add('scale-105', 'shadow-lg');
  }

  function drag(e) {
    if (!isDragging) return;

    // 防止选择文本
    e.preventDefault();

    // 获取父容器位置
    const container = freeDraggable.parentElement;
    const containerRect = container.getBoundingClientRect();

    // 计算新位置（相对于容器）
    let newX = e.clientX - containerRect.left - offsetX;
    let newY = e.clientY - containerRect.top - offsetY;

    // 限制在容器内
    newX = Math.max(0, Math.min(newX, containerRect.width - freeDraggable.offsetWidth));
    newY = Math.max(0, Math.min(newY, containerRect.height - freeDraggable.offsetHeight));

    // 设置新位置
    freeDraggable.style.left = `${newX}px`;
    freeDraggable.style.top = `${newY}px`;
  }

  function endDrag() {
    isDragging = false;
    freeDraggable.classList.remove('scale-105', 'shadow-lg');
  }

  // 拖放排序功能
  const sortableList = document.getElementById('sortableList');
  let draggedItem = null;

  // 为所有可排序项目添加事件监听
  document.querySelectorAll('#sortableList .draggable').forEach(item => {
    item.addEventListener('dragstart', handleDragStart);
    item.addEventListener('dragover', handleDragOver);
    item.addEventListener('dragenter', handleDragEnter);
    item.addEventListener('dragleave', handleDragLeave);
    item.addEventListener('drop', handleDrop);
    item.addEventListener('dragend', handleDragEnd);
  });

  function handleDragStart(e) {
    draggedItem = this;
    // 设置拖动数据
    e.dataTransfer.setData('text/plain', this.textContent.trim());

    // 添加拖动样式
    setTimeout(() => {
      this.classList.add('opacity-70', 'scale-95');
    }, 0);
  }

  function handleDragOver(e) {
    e.preventDefault(); // 允许放置
  }

  function handleDragEnter(e) {
    e.preventDefault();
    if (this !== draggedItem) {
      this.classList.add('bg-gray-100');
    }
  }

  function handleDragLeave() {
    this.classList.remove('bg-gray-100');
  }

  function handleDrop(e) {
    e.preventDefault();
    this.classList.remove('bg-gray-100');

    if (this !== draggedItem) {
      // 获取两个元素的位置并交换
      const items = Array.from(sortableList.children);
      const draggedIndex = items.indexOf(draggedItem);
      const dropIndex = items.indexOf(this);

      if (draggedIndex < dropIndex) {
        sortableList.insertBefore(draggedItem, this.nextSibling);
      } else {
        sortableList.insertBefore(draggedItem, this);
      }
    }
  }

  function handleDragEnd() {
    // 移除拖动样式
    this.classList.remove('opacity-50', 'scale-95');
    // 为新位置的元素重新添加事件监听
    document.querySelectorAll('#sortableList .draggable').forEach(item => {
      item.removeEventListener('dragstart', handleDragStart);
      item.removeEventListener('dragover', handleDragOver);
      item.removeEventListener('dragenter', handleDragEnter);
      item.removeEventListener('dragleave', handleDragLeave);
      item.removeEventListener('drop', handleDrop);
      item.removeEventListener('dragend', handleDragEnd);
    });

    document.querySelectorAll('#sortableList .draggable').forEach(item => {
      item.addEventListener('dragstart', handleDragStart);
      item.addEventListener('dragover', handleDragOver);
      item.addEventListener('dragenter', handleDragEnter);
      item.addEventListener('dragleave', handleDragLeave);
      item.addEventListener('drop', handleDrop);
      item.addEventListener('dragend', handleDragEnd);
    });
  }

  // 拖放分类功能
  const dropZones = document.querySelectorAll('.drop-zone');
  let draggedElement = null;

  // 为所有可拖动元素添加事件
  document.querySelectorAll('.draggable[draggable="true"]').forEach(item => {
    item.addEventListener('dragstart', (e) => {
      draggedElement = item;
      e.dataTransfer.setData('text/plain', item.dataset.type);
      setTimeout(() => {
        item.classList.add('opacity-50', 'scale-95');
      }, 0);
    });

    item.addEventListener('dragend', () => {
      item.classList.remove('opacity-50', 'scale-95');
      // 重置所有drop zone样式
      dropZones.forEach(zone => {
        zone.classList.remove('highlight');
      });
    });
  });

  // 为所有drop zone添加事件
  dropZones.forEach(zone => {
    zone.addEventListener('dragover', (e) => {
      e.preventDefault();

      // 检查是否可以接受该类型
      const itemType = draggedElement ? draggedElement.dataset.type : '';
      const zoneAccept = zone.dataset.accept;

      if (!zoneAccept || zoneAccept === itemType) {
        zone.classList.add('highlight');
      }
    });

    zone.addEventListener('dragenter', (e) => {
      e.preventDefault();
      const itemType = draggedElement ? draggedElement.dataset.type : '';
      const zoneAccept = zone.dataset.accept;

      if (!zoneAccept || zoneAccept === itemType) {
        zone.classList.add('highlight');
      }
    });

    zone.addEventListener('dragleave', () => {
      zone.classList.remove('highlight');
    });

    zone.addEventListener('drop', (e) => {
      e.preventDefault();
      zone.classList.remove('highlight');

      // 检查是否可以接受该类型
      const itemType = draggedElement.dataset.type;
      const zoneAccept = zone.dataset.accept;

      if (!zoneAccept || zoneAccept === itemType) {
        // 如果是垃圾桶区域，执行删除
        if (zone.id === 'trashZone') {
          if (draggedElement) {
            // 添加删除动画
            draggedElement.classList.add('scale-90', 'opacity-0');
            setTimeout(() => {
              draggedElement.remove();
            }, 200);
            draggedElement = null;
          }
          return;
        }

        // 找到区域内的容器（最后一个子元素是容器）
        const container = zone.querySelector('.space-y-2') || zone;

        // 如果拖动元素存在，添加到目标区域
        if (draggedElement && !container.contains(draggedElement)) {
          // 创建元素副本
          const clone = draggedElement.cloneNode(true);

          // 为副本添加拖动事件
          clone.addEventListener('dragstart', (e) => {
            draggedElement = clone;
            e.dataTransfer.setData('text/plain', clone.dataset.type);
            setTimeout(() => {
              clone.classList.add('opacity-50', 'scale-95');
            }, 0);
          });

          clone.addEventListener('dragend', () => {
            clone.classList.remove('opacity-50', 'scale-95');
          });

          // 添加到容器
          container.appendChild(clone);

          // 如果是从源区域拖动，删除原元素
          if (zone.dataset.accept) {
            draggedElement.remove();
          }

          draggedElement = null;
        }
      }
    });
  });
</script>
</body>
</html>
